package crud.controller;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import crud.bean.Employee;
import crud.bean.Message;
import crud.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.*;

/**
 * EmployeeController
 *
 * @author Yin Guiqing
 */
@Controller
public class EmployeeController {
    @Autowired
    EmployeeService employeeService;

    /*
      注解 @ResponseBody 的作用是将 controller 方法返回的对象通过适当的转换器转换为指定的格式之后，
      写入到 response 对象的 body 区，通常用来返回 JSON 数据或者是 XML
     */

    /**
     * 获取全部员工（分页查询）
     *
     * @param pageNum 查询页数
     * @return 自定义封装 JSON
     */
    @RequestMapping("/employees")
    @ResponseBody
    public Message getAllEmployeesJson(
            @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum) {
        // 使用 PageHelper 工具进行分页
        PageHelper.startPage(pageNum, 10);
        // startPage() 方法后紧跟的这个查询就是分页查询
        List<Employee> allEmployees = employeeService.getAllEmployees();
        // 使用 PageInfo 包装查询后的结果，只需将 pageInfo 交给页面即可
        PageInfo<Employee> pageInfo = new PageInfo<>(allEmployees, 5);

        return Message.success().add("pageInfo", pageInfo);
    }

    // @RequestMapping("/employees")
    @Deprecated
    public String getAllEmployees(@RequestParam(value = "pageNum",
            defaultValue = "1") Integer pageNum, Model model) {
        // 使用 PageHelper 工具进行分页
        PageHelper.startPage(pageNum, 10);
        // startPage() 方法后紧跟的这个查询就是分页查询
        List<Employee> allEmployees = employeeService.getAllEmployees();
        // 使用 PageInfo 包装查询后的结果，只需将 pageInfo 交给页面即可
        PageInfo<Employee> pageInfo = new PageInfo<>(allEmployees, 5);

        model.addAttribute("pageInfo", pageInfo);
        return "list";
    }

    @RequestMapping(value = "/employees/{empId}", method = RequestMethod.GET)
    @ResponseBody
    public Message getEmpById(@PathVariable("empId") Integer empId) {
        Employee employee = employeeService.getEmpById(empId);
        return Message.success().add("employee", employee);
    }

    /**
     * 保存新增员工
     * <p>
     * 1. 支持 JSR303 校验
     * 2. Hibernate-Validator
     *
     * @param employee 封装的员工对象
     * @return 自定义信息 JSON
     */
    @ResponseBody
    @RequestMapping(value = "/employees", method = RequestMethod.POST)
    public Message saveEmployee(@Valid Employee employee,
                                BindingResult result) {
        if (result.hasErrors()) {
            // 校验失败
            Map<String, Object> map = new HashMap<>();
            List<FieldError> fieldErrors = result.getFieldErrors();
            for (FieldError fieldError : fieldErrors) {
                map.put(fieldError.getField(), fieldError.getDefaultMessage());
            }
            return Message.fail().add("fieldErrors", map);
        } else {
            // 校验成功
            employeeService.saveEmployee(employee);
            return Message.success();
        }
    }

    /**
     * 如果直接发送ajax=PUT形式的请求
     * 封装的数据
     * Employee
     * [empId=1014, empName=null, gender=null, email=null, dId=null]
     *
     * 问题：
     * 请求体中有数据；
     * 但是Employee对象封装不上；
     * update tbl_emp  where emp_id = 1014;
     *
     * 原因：
     * Tomcat：
     * 		1、将请求体中的数据，封装一个map。
     * 		2、request.getParameter("empName")就会从这个map中取值。
     * 		3、SpringMVC封装POJO对象的时候。
     * 				会把POJO中每个属性的值，request.getParamter("email");
     * AJAX发送PUT请求引发的血案：
     * 		PUT请求，请求体中的数据，request.getParameter("empName")拿不到
     * 		Tomcat一看是PUT不会封装请求体中的数据为map，只有POST形式的请求才封装请求体为map
     * org.apache.catalina.connector.Request--parseParameters() (3111);
     *
     * protected String parseBodyMethods = "POST";
     * if( !getConnector().isParseBodyMethod(getMethod()) ) {
           success = true;
           return;
       }
     *
     *
     * 解决方案；
     * 我们要能支持直接发送PUT之类的请求还要封装请求体中的数据
     * 1、配置上HttpPutFormContentFilter；
     * 2、他的作用；将请求体中的数据解析包装成一个map。
     * 3、request被重新包装，request.getParameter()被重写，就会从自己封装的map中取数据
     *
     * 更新
     *
     * @param employee 封装的员工对象
     * @return 自定义信息 JSON
     */
    @ResponseBody
    @RequestMapping(value = "/employees/{empId}", method = RequestMethod.PUT)
    public Message updateEmployee(Employee employee) {
        int i = employeeService.updateEmployee(employee);
        return Message.success();
    }

    /**
     * 删除员工（一个或多个皆可）
     * @param empIds 要删除的员工id，形如 "1-2-3"
     * @return 自定义信息 JSON
     */
    @ResponseBody
    @RequestMapping(value = "/employees/{empIds}", method = RequestMethod.DELETE)
    public Message deleteById(@PathVariable("empIds") String empIds) {
        if (empIds.contains("-")) {
            // 批量删除
            String[] split = empIds.split("-");
            List<Integer> listEmpId = new ArrayList<>();
            for (String s : split) {
                listEmpId.add(Integer.parseInt(s));
            }
            int i = employeeService.deleteBatch(listEmpId);
        } else {
            // 单个删除
            int i = employeeService.deleteById(Integer.parseInt(empIds));
        }
        return Message.success();
    }

    /**
     * 初步检查是否合法
     *
     * @param empName 姓名
     * @return 自定义信息 JSON
     */
    @ResponseBody
    @RequestMapping("/checkUser")
    public Message checkUser(@RequestParam("empName") String empName) {
        // 正则表达式判断是否合法
        String reg = "^[\\u4E00-\\u9FA5a-zA-Z0-9_-]{2,16}$";
        if (!empName.matches(reg)) {
            return Message.fail().add("vaMsg", "姓名需要是2-16位中文或英文");
        }
        // 检查是否已存在
        boolean b = employeeService.checkUser(empName);
        if (b) {
            return Message.success().add("vaMsg", "可以");
        } else {
            return Message.fail().add("vaMsg", "已存在");
        }
    }
}
